
package com.trydofor.id.a9cq;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.annotation.concurrent.ThreadSafe;

import com.trydofor.id.core.A9CQ;

/**
 * an atomic(lock-free) fixed entry a9cq.
 * 
 * @param <E> the Element of sequence
 * @author Shi Rongjiu (www.trydofor.com)
 * @since 0.9
 */
@ThreadSafe
public final class FixedEntryA9cq<E> implements A9CQ<E> {
    
    //
    private final boolean       isCyclic;
    private final FixedLongA9cq index;
    private final ArrayList<E>  items;
    
    /**
     * an atomic(lock-free) fixed entry a9cq.
     * 
     * @param isCyclic cyclic generation or not.
     * @param e the first value.
     * @param ts the other values.
     */
    public FixedEntryA9cq(boolean isCyclic, E e, E... ts) {
        this.isCyclic = isCyclic;
        items = new ArrayList<E>(ts.length + 1);
        items.add(e);
        for (int i = 0; i < ts.length; i++) {
            items.add(ts[i]);
        }
        index = new FixedLongA9cq(isCyclic, 0, items.size() - 1, 1);
    }
    
    /**
     * an atomic(lock-free) fixed entry a9cq.
     * 
     * @param isCyclic cyclic generation or not.
     * @param ts the values.
     */
    public FixedEntryA9cq(boolean isCyclic, Collection<E> ts) {
        this.isCyclic = isCyclic;
        items = new ArrayList<E>(ts.size());
        items.addAll(ts);
        index = new FixedLongA9cq(isCyclic, 0, items.size() - 1, 1);
    }
    
    /**
     * whether cyclically generate sequence.
     * 
     * @return true if cyclic.
     */
    public boolean isCyclic() {
        return isCyclic;
    }
    
    /**
     * {@inheritDoc}
     */
    public boolean isAtomic() {
        return true;
    }
    
    /**
     * <pre>
     * return the count ,if cyclic is:
     * - true  - entire item.
     * - false - unused item.
     * </pre>
     * 
     * {@inheritDoc}
     */
    public long remains() {
        return index.remains();
    }
    
    /**
     * {@inheritDoc}
     */
    public E current() {
        final Long idx = index.current();
        return getValue(idx);
    }
    
    /**
     * {@inheritDoc}
     */
    public E next() {
        final Long idx = index.next();
        return getValue(idx);
    }
    
    /**
     * {@inheritDoc}
     */
    public E next(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
        final Long idx = index.next(timeout, unit);
        return getValue(idx);
    }
    
    /**
     * {@inheritDoc}
     */
    public void reset() {
        index.reset();
    }
    
    /**
     * {@inheritDoc}
     */
    public String toString() {
        final Long idx = index.current();
        final int siz = items.size();
        StringBuilder sb = new StringBuilder();
        sb.append("isCyclic=");
        sb.append(isCyclic);
        sb.append(",remains=");
        sb.append((isCyclic ? siz : (idx == null ? 0 : siz - idx.intValue() - 1)));
        sb.append(",current=");
        sb.append(getValue(idx));
        
        return sb.toString();
    }
    
    // -----------------
    private E getValue(Long idx) {
        if (idx == null) return null;
        return items.get(idx.intValue());
    }
}
